package com.dietmanager.view;

import java.util.ArrayList;
import java.util.Date;
import java.util.Observable;
import java.util.Observer;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;
import java.time.LocalDate;

import com.dietmanager.model.Food;
import com.dietmanager.model.FoodModel;
import com.dietmanager.model.ExerciseModel;
import com.dietmanager.model.javafx.util.DailyLog;
import com.dietmanager.model.javafx.util.WorkoutListEntry;

/**
 * 
 * @author Danijel, Petar
 * @description Implements the View class. It is the main view, holds also GUI
 *              and operating methods for using the program.
 *
 */

public class MainView extends Observable {

	ArrayList<Observer> observerList = new ArrayList<Observer>();

	private ObservableList<DailyLog> data = FXCollections.observableArrayList();
	private ObservableList<WorkoutListEntry> dataExercises = FXCollections.observableArrayList();

	// Variables and objects
	public Button addRecipe, showDaily, addToDailyLog, addExercise, addWorkout, addWorkoutToDailyLog;
	public TableView dailyLogTable = showDailyTable();
	public TableView dailyWorkoutTable = showDailyWorkoutTable();
	public ComboBox recipeFoodBox, exerciseWorkoutBox;
	public TextField weightTextField, calorieLimitTextField;
	public ObservableList<String> recipeFoodList = FXCollections
			.observableArrayList();
	public ObservableList<String> exerciseWorkoutList = FXCollections
			.observableArrayList();
	public AddRecipeView addRecipeView;
	public AddFoodView addFoodView;
	public AddExerciseView addExerciseView;
	public AddWorkoutView addWorkoutView;
	public TableView table, workoutTable;
	public TableColumn fatColumn, amountColumn, carbohydratesColumn,
			proteinsColumn, caloriesColumn, foodColumn, workoutCaloriesColumn,
			repetitionsColumn, minutesColumn, workoutNameColumn;
	public HBox lowBar;
	public VBox centerPane;
	public DatePicker datePicker;

	public MainView(Stage primaryStage) {
		primaryStage.setTitle("Diet Manager");

		// First layout setup
		BorderPane borderPane = new BorderPane();
		borderPane.getStyleClass().add("borderPane");
		addRecipeView = new AddRecipeView();
		addFoodView = new AddFoodView();
		addExerciseView = new AddExerciseView();
		addWorkoutView = new AddWorkoutView();
		centerPane = new VBox();

		// Center Panel
		centerPane.getChildren().addAll(dailyLogTable, dailyWorkoutTable);

		// Top bar
		HBox hbox = addHbox();
		hbox.getStyleClass().add("topBar");

		// Sidebar
		VBox vbox = addVbox(borderPane, centerPane,
				addRecipeView.getAddRecipeView(), addFoodView.getAddFoodView(),
				addExerciseView.getAddExerciseView(),
				addWorkoutView.getAddWorkoutView());
		vbox.getStyleClass().add("sidebar");

		// Bottom bar
		lowBar = addLowBar();
		lowBar.getStyleClass().add("footer");

		borderPane.setTop(hbox);
		borderPane.setLeft(vbox);
		borderPane.setBottom(lowBar);

		/*
		 * Load the screens
		 */
		borderPane.setCenter(centerPane);

		Scene scene = new Scene(borderPane);

		scene.getStylesheets().add(
				MainView.class.getResource("application.css").toExternalForm());

		primaryStage.setScene(scene);
		primaryStage.centerOnScreen();
		primaryStage.setHeight(650);
		primaryStage.setWidth(1100);
		primaryStage.setFullScreen(true);
		primaryStage.fullScreenExitHintProperty();
		primaryStage.show();
	}

	public HBox addHbox() {

		HBox hbox = new HBox();

		hbox.setPadding(new Insets(30));
		hbox.setAlignment(Pos.BOTTOM_RIGHT);

		datePicker = new DatePicker(LocalDate.now());
		datePicker.setVisible(true);

		datePicker.setOnAction(new EventHandler() {
			public void handle(Event t) {
				LocalDate date = datePicker.getValue();
				Date d = new Date();
				d.setDate(date.getDayOfMonth());
				d.setMonth(date.getMonthValue());
				d.setYear(date.getYear());
				
				MainView.this.notifyObservers(d);
			}
		});
		
		/**
		 * Button for creating summary log for selected day. unfortunatelly, it hasnt been implemented
		 */
		Button createSummaryLog = new Button("Create Summary Log");
		createSummaryLog.getStyleClass().add("customButton");
		hbox.setSpacing(10);
		hbox.getChildren().addAll(datePicker,createSummaryLog);
		return hbox;
	}

	public VBox addVbox(BorderPane borderPane, VBox dailyLogView,
			VBox addRecipeView, VBox addFoodView, VBox addExerciseView,
			VBox addWorkoutView) {

		VBox vbox = new VBox();

		vbox.setPadding(new Insets(30));
		vbox.setAlignment(Pos.TOP_CENTER);
		vbox.setSpacing(8);
		vbox.setMaxWidth(300);
		vbox.setMinWidth(300);

		showDaily = new Button("Show Daily Log");
		showDaily.getStyleClass().add("customButton");
		showDaily.setMaxWidth(200);

		showDaily.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				borderPane.setCenter(dailyLogView);
				// Show what must be seen
				HBox hBox = (HBox) borderPane.getChildren().get(0);
				hBox.getChildren().get(0).setVisible(true);
				hBox = (HBox) borderPane.getChildren().get(2);
				hBox.getChildren().get(0).setVisible(true);
				hBox.getChildren().get(1).setVisible(true);
				hBox.getChildren().get(2).setVisible(true);
			}

		});

		addRecipe = new Button("Add Recipe");
		addRecipe.getStyleClass().add("customButton");
		addRecipe.setMaxWidth(200);

		final AddRecipeView arv = this.addRecipeView;

		addRecipe.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				borderPane.setCenter(addRecipeView);

				// Hide what must be hidden
				HBox hBox = (HBox) borderPane.getChildren().get(0);
				hBox.getChildren().get(0).setVisible(false);
				hBox = (HBox) borderPane.getChildren().get(2);
				hBox.getChildren().get(0).setVisible(false);
				hBox.getChildren().get(1).setVisible(false);
				hBox.getChildren().get(2).setVisible(false);
				// borderPane.getBottom().setVisible(false); //test
				// borderPane.getTop().setVisible(false); //test

				arv.addObserverCollection(observerList);
			}

		});

		Button addFood = new Button("Add Food");
		addFood.getStyleClass().add("customButton");
		addFood.setMaxWidth(200);

		final AddFoodView afv = this.addFoodView;

		addFood.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				borderPane.setCenter(addFoodView);

				// Hide what must be hidden
				HBox hBox = (HBox) borderPane.getChildren().get(0);
				hBox.getChildren().get(0).setVisible(false);
				hBox = (HBox) borderPane.getChildren().get(2);
				hBox.getChildren().get(0).setVisible(false);
				hBox.getChildren().get(1).setVisible(false);
				hBox.getChildren().get(2).setVisible(false);
				// borderPane.getBottom().setVisible(false); //test
				// borderPane.getTop().setVisible(false); //test

				afv.addObserverCollection(observerList);
			}

		});

		addWorkout = new Button("Add Workout");
		addWorkout.getStyleClass().add("customButton");
		addWorkout.setMaxWidth(200);

		final AddWorkoutView awv = this.addWorkoutView;
		addWorkout.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				borderPane.setCenter(addWorkoutView);

				// Hide what must be hidden
				HBox hBox = (HBox) borderPane.getChildren().get(0);
				hBox.getChildren().get(0).setVisible(false);
				hBox = (HBox) borderPane.getChildren().get(2);
				hBox.getChildren().get(0).setVisible(false);
				hBox.getChildren().get(1).setVisible(false);
				hBox.getChildren().get(2).setVisible(false);
				// borderPane.getBottom().setVisible(false); //test
				// borderPane.getTop().setVisible(false); //test

				awv.addObserverCollection(observerList);
			}

		});

		// Add Exercise button configuration and listener
		addExercise = new Button("Add Exercise");
		addExercise.getStyleClass().add("customButton");
		addExercise.setMaxWidth(200);

		final AddExerciseView aev = this.addExerciseView;
		addExercise.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				borderPane.setCenter(addExerciseView);

				// Hide what must be hidden
				HBox hBox = (HBox) borderPane.getChildren().get(0);
				hBox.getChildren().get(0).setVisible(false);
				hBox = (HBox) borderPane.getChildren().get(2);
				hBox.getChildren().get(0).setVisible(false);
				hBox.getChildren().get(1).setVisible(false);
				hBox.getChildren().get(2).setVisible(false);
				// borderPane.getBottom().setVisible(false); //test
				// borderPane.getTop().setVisible(false); //test

				aev.addObserverCollection(observerList);
			}

		});

		vbox.getChildren().addAll(showDaily, addRecipe, addFood, addExercise,
				addWorkout);

		return vbox;
	}

	// Footer
	public HBox addLowBar() {

		HBox hbox = new HBox();
		hbox.getStyleClass().add("bottomBar");
		hbox.setAlignment(Pos.CENTER);

		// label and textfield for weight
		Label weightLabel = new Label("Weight: ");
		weightLabel.getStyleClass().add("tLabel");
		weightTextField = new TextField();
		weightTextField.setPromptText("Enter desired weight");
		// label and textfield for calorie limit
		Label calorieLimit = new Label("Desired Calorie Limit");
		calorieLimit.getStyleClass().add("tLabel");
		calorieLimitTextField = new TextField();
		calorieLimitTextField.setPromptText("Enter calorie limit");

		recipeFoodBox = new ComboBox(recipeFoodList);
		recipeFoodBox.setValue("Pick Food/Recipe");

		// Button for adding to daily log
		addToDailyLog = new Button("Add Food/Recipe To Daily Log");
		addToDailyLog.getStyleClass().add("customButton");
		// Button event
		addToDailyLog.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				notifyObservers(recipeFoodBox.getValue().toString());
			}

		});
		
		//ComboBox and Button for adding exercise/workout
		exerciseWorkoutBox = new ComboBox(exerciseWorkoutList);
		exerciseWorkoutBox.setValue("Pick Exercise/Workout");
		
		addWorkoutToDailyLog = new Button("Add Exercise/Workout To Daily Log");
		addWorkoutToDailyLog.getStyleClass().add("customButton");
		//Button event
		addWorkoutToDailyLog.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				// Sending stringbuilder to be able to distinguish from 
				// event that uses regular string
				StringBuilder sb = new StringBuilder();
				sb.append(exerciseWorkoutBox.getValue().toString());
				notifyObservers(sb);
			}

		});
		
		// Adding items to lowerPane left side
		GridPane leftGrid = new GridPane();
		leftGrid.setPadding(new Insets(0));

		leftGrid.add(weightLabel, 1, 1);
		leftGrid.add(weightTextField, 2, 1);
		leftGrid.add(calorieLimit, 1, 2);
		leftGrid.add(calorieLimitTextField, 2, 2);
		
		//Contained for right side items
		VBox rightGrid = new VBox();
		rightGrid.setSpacing(5);
		rightGrid.setAlignment(Pos.CENTER);
		rightGrid.getChildren().addAll(recipeFoodBox, addToDailyLog, exerciseWorkoutBox, addWorkoutToDailyLog);

		// Adding items to lowerPane right side
		hbox.getChildren().addAll(leftGrid, rightGrid);

		hbox.setMargin(leftGrid, new Insets(0, 200, 10, 50));
		return hbox;
	}

	// called when the user selects to show daily log and on app start
	public TableView<DailyLog> showDailyTable() {

		TableView<DailyLog> table = new TableView<DailyLog>();
		table.getStyleClass().add("dailyLogTable");

		foodColumn = new TableColumn("Food");
		caloriesColumn = new TableColumn("Calories");
		amountColumn = new TableColumn("Amount");
		fatColumn = new TableColumn("Fat");
		carbohydratesColumn = new TableColumn("Carobhydrates");
		proteinsColumn = new TableColumn("Proteins");

		foodColumn.setResizable(true);
		caloriesColumn.setResizable(true);
		amountColumn.setResizable(true);
		carbohydratesColumn.setResizable(true);
		fatColumn.setResizable(true);
		proteinsColumn.setResizable(true);

		foodColumn.getStyleClass().add("foodColumn");
		caloriesColumn.getStyleClass().add("caloriesColumn");

		foodColumn
				.setCellValueFactory(new PropertyValueFactory<DailyLog, String>(
						"food"));
		caloriesColumn
				.setCellValueFactory(new PropertyValueFactory<DailyLog, String>(
						"calories"));
		amountColumn
				.setCellValueFactory(new PropertyValueFactory<DailyLog, String>(
						"amount"));
		fatColumn
				.setCellValueFactory(new PropertyValueFactory<DailyLog, String>(
						"fat"));
		carbohydratesColumn
				.setCellValueFactory(new PropertyValueFactory<DailyLog, String>(
						"carbohydrates"));
		proteinsColumn
				.setCellValueFactory(new PropertyValueFactory<DailyLog, String>(
						"proteins"));

		table.getColumns().addAll(foodColumn, amountColumn, caloriesColumn,
				carbohydratesColumn, fatColumn, proteinsColumn);
		table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

		table.setItems(data);

		return table;
	}

	// Workout and Exercise table
	public TableView<WorkoutListEntry> showDailyWorkoutTable() {
		// Workout and Exercise table
		TableView<WorkoutListEntry> workoutTable = new TableView<WorkoutListEntry>();
		workoutTable.getStyleClass().add("dailyLogTable");

		workoutNameColumn = new TableColumn("Workout/Exercise Name");
		workoutCaloriesColumn = new TableColumn("Calories burnt");
		repetitionsColumn = new TableColumn("Repetitions per Workout");
		minutesColumn = new TableColumn("Minutes per Exercise");

		workoutTable.getColumns().addAll(workoutNameColumn,
				workoutCaloriesColumn, repetitionsColumn, minutesColumn);
		workoutTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

		// Data inserts here
		workoutNameColumn
				.setCellValueFactory(new PropertyValueFactory<WorkoutListEntry, String>(
						"name"));
		workoutCaloriesColumn
				.setCellValueFactory(new PropertyValueFactory<WorkoutListEntry, String>(
						"calories"));
		repetitionsColumn
				.setCellValueFactory(new PropertyValueFactory<WorkoutListEntry, String>(
						"repetitions"));
		minutesColumn
				.setCellValueFactory(new PropertyValueFactory<WorkoutListEntry, String>(
						"minutes"));

		workoutTable.setItems(dataExercises);

		return workoutTable;
	}

	// Date creation
	public Date getSelectedDate() {
		LocalDate date = datePicker.getValue();
		Date d = new Date();
		d.setDate(date.getDayOfMonth());
		d.setMonth(date.getMonthValue());
		d.setYear(date.getYear());
		return d;
	}

	// Displaying the log
	public void displayDailyLog(ArrayList<FoodModel> fm, ArrayList<ExerciseModel> em) {
		data.clear();

		if (fm != null)
			for (FoodModel f : fm)
				if(f != null)
					data.add(new DailyLog(f.getName(), f.getCalories() + "", f
							.getAmount() + "", f.getCarbohydrates() + "", f
							.getFat() + "", f.getProtein() + ""));
		
		dataExercises.clear();
		
		if(em != null)
			for(ExerciseModel e : em)
				if(e != null)
					dataExercises.add(new WorkoutListEntry(e.getName(), e.getCalories()+"",
						e.getMinutes()+"", e.getRepetitions()+""));
	}

	// Updating the list
	public void updateFoodList(ArrayList<FoodModel> fm) {
		recipeFoodList.clear();

		if (fm != null)
			for (FoodModel f : fm)
				recipeFoodList.add(f.getName());

		this.addRecipeView.updateFoodList(fm);
	}
	
	// Updating the list
	public void updateExerciseList(ArrayList<ExerciseModel> wm) {
		exerciseWorkoutList.clear();

		if (wm != null)
			for (ExerciseModel f : wm)
				exerciseWorkoutList.add(f.getName());

		this.addWorkoutView.updateExerciseList(wm);
	}

	// Add observer
	public void addObserver(Observer o) {
		observerList.add(o);
	}

	// Propagate observer changes
	public void notifyObservers(Object o) {
		for (Observer ob : observerList)
			ob.update(this, o);
	}

}
